Introduction

Objectives

  • Visualizing spatial and temporal trends of criminal activity
  • Analyzing factors that may affect unlawful behavior

Study Area

Software Needed

Download R and RStudio

First, you’ll download and set up R and RStudio, a free integrated development environment for R. RStudio helps you work in R by providing a coding platform with access to CRAN, the Comprehensive R Archive Network, which contains thousands of R libraries, a built-in viewer for charts and graphs, and other useful features.

  • If necessary, download R 3.5.0 or later. Accept all defaults in the installation wizard.

  • If necessary, download RStudio Desktop. Accept all defaults in the installation wizard.

Install R libraries

if (!require(readr)) install.packages("readr")
if (!require(dplyr)) install.packages("dplyr")
if (!require(DT)) install.packages("DT")
if (!require(ggrepel)) install.packages("ggrepel")
if (!require(leaflet)) install.packages("leaflet")

Data Preprocessing

Read the data

Load the data using readr and read_csv().

library(readr)
path <- "/path/to/crime/data/SF_Crime_2003_2018.csv"
df <- read_csv(path)

Display Data

Display the data using DT and datatable().

library(DT)
df_sub <- df[1:100,]  # display the first 100 rows
df_sub$Time <- as.character(df_sub$Time) 
datatable(df_sub, options = list(pageLength = 5,scrollX = '400px'))

sprintf("Number of Rows in Dataframe: %s", format(nrow(df),big.mark = ","))
[1] "Number of Rows in Dataframe: 2,215,024"

Preprocess Data

The All-Caps text is difficult to read. Let’s force the text in the appropriate columns into proper case.

# str(df)
proper_case <- function(x) {
  return (gsub("\\b([A-Z])([A-Z]+)", "\\U\\1\\L\\2" , x, perl=TRUE))
}
library(dplyr)
df <- df %>% mutate(Category = proper_case(Category),
                    Descript = proper_case(Descript),
                    PdDistrict = proper_case(PdDistrict),
                    Resolution = proper_case(Resolution),
                    Time = as.character(Time))
df_sub <- df[1:100,]  # display the first 100 rows
datatable(df_sub, options = list(pageLength = 5,scrollX='400px'))

Visualize Data

Crime across space

Display crime incident locations on the map using leaflet. Click icons on the map to show incident details.

library(leaflet)
data <- df[1:10000,] # display the first 10,000 rows
data$popup <- paste("<b>Incident #: </b>", data$IncidntNum, "<br>", "<b>Category: </b>", data$Category,
                    "<br>", "<b>Description: </b>", data$Descript,
                    "<br>", "<b>Day of week: </b>", data$DayOfWeek,
                    "<br>", "<b>Date: </b>", data$Date,
                    "<br>", "<b>Time: </b>", data$Time,
                    "<br>", "<b>PD district: </b>", data$PdDistrict,
                    "<br>", "<b>Resolution: </b>", data$Resolution,
                    "<br>", "<b>Address: </b>", data$Address,
                    "<br>", "<b>Longitude: </b>", data$X,
                    "<br>", "<b>Latitude: </b>", data$Y)
leaflet(data, width = "100%") %>% addTiles() %>%
  addTiles(group = "OSM (default)") %>%
  addProviderTiles(provider = "Esri.WorldStreetMap",group = "World StreetMap") %>%
  addProviderTiles(provider = "Esri.WorldImagery",group = "World Imagery") %>%
  # addProviderTiles(provider = "NASAGIBS.ViirsEarthAtNight2012",group = "Nighttime Imagery") %>%
  addMarkers(lng = ~X, lat = ~Y, popup = data$popup, clusterOptions = markerClusterOptions()) %>%
  addLayersControl(
    baseGroups = c("OSM (default)","World StreetMap", "World Imagery"),
    options = layersControlOptions(collapsed = FALSE)
  )

Crime Over Time

library(dplyr)
df_crime_daily <- df %>%
  mutate(Date = as.Date(Date, "%m/%d/%Y")) %>%
  group_by(Date) %>%
  summarize(count = n()) %>%
  arrange(Date)
library(ggplot2)
library(scales)
plot_daily_crimes <- ggplot(df_crime_daily, aes(x = Date, y = count)) +
  geom_line(color = "#F2CA27", size = 0.1) +
  geom_smooth(color = "#1A1A1A") +
  # fte_theme() +
  scale_x_date(breaks = date_breaks("1 year"), labels = date_format("%Y")) +
  labs(x = "Date of Crime", y = "Number of Crimes", title = "Daily Crimes in San Francisco (2003 – 2018)")
plot_daily_crimes

Aggregate Data

Summarize the data by incident category.

df_category <- sort(table(df$Category),decreasing = TRUE)
df_category <- data.frame(df_category[df_category > 10000])
colnames(df_category) <- c("Category", "Frequency")
df_category$Percentage <- df_category$Frequency / sum(df_category$Frequency)
datatable(df_category, options = list(scrollX = '400px'))

Create a bar plot based on the incident category.

library(ggplot2)
library(ggrepel)
bp<-ggplot(df_category, aes(x=Category, y=Frequency, fill=Category)) + geom_bar(stat="identity") + 
  theme(axis.text.x=element_blank()) + geom_text_repel(data=df_category, aes(label=Category))
bp

Create a pie chart based on the incident category.

bp<-ggplot(df_category, aes(x="", y=Percentage, fill=Category)) + geom_bar(stat="identity") 
pie <- bp + coord_polar("y") 
pie

Correlation Analysis

Factor by Crime Category

Certain types of crime may be more time dependent. (e.g., more traffic violations when people leave work)

df_top_crimes <- df_arrest %>%
  group_by(Category) %>% 
  summarize(count = n()) %>%
  arrange(desc(count))
datatable(df_top_crimes, options = list(pageLength = 10,scrollX = '400px'))
df_arrest_time_crime <- df_arrest %>%
  filter(Category %in% df_top_crimes$Category[2:19]) %>%
  mutate(Hour = sapply(Time, get_hour)) %>%
  group_by(Category, DayOfWeek, Hour) %>% 
  summarize(count = n())
df_arrest_time_crime$DayOfWeek <- factor(df_arrest_time_crime$DayOfWeek, level = rev(dow_format))
df_arrest_time_crime$Hour <- factor(df_arrest_time_crime$Hour, level = 0:23, label = hour_format)
datatable(df_arrest_time_crime, options = list(pageLength = 10,scrollX = '400px'))
plot_num_arrests <- ggplot(df_arrest_time_crime, aes(x = Hour, y = DayOfWeek, fill = count)) +
  geom_tile() +
  # fte_theme() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.6, size = 4)) +
  labs(x = "Hour of Arrest (Local Time)", y = "Day of Week of Arrest", title = "Number of Police Arrests in San Francisco by Category and Time of Arrest (2003-2018)") +
  scale_fill_gradient(low = "white", high = "#2980B9") +
  facet_wrap(~ Category, nrow = 6)
plot_num_arrests

Good, but the gradients aren’t helpful because they are not normalized. We need to normalize the range on each facet. (unfortunately, this makes the value of the gradient unhelpful)

df_arrest_time_crime <- df_arrest_time_crime %>%
  group_by(Category) %>%
  mutate(norm = count/sum(count))
datatable(df_arrest_time_crime, options = list(pageLength = 10,scrollX = '400px'))
plot <- ggplot(df_arrest_time_crime, aes(x = Hour, y = DayOfWeek, fill = norm)) +
  geom_tile() +
  # fte_theme() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.6, size = 4)) +
  labs(x = "Hour of Arrest (Local Time)", y = "Day of Week of Arrest", title = "Police Arrests in San Francisco by Time of Arrest, Normalized by Type of Crime (2003-2018)") +
  scale_fill_gradient(low = "white", high = "#2980B9") +
  facet_wrap(~ Category, nrow = 6)
plot

Factor by Police District

Same as above, but with a different facet.

df_arrest_time_district <- df_arrest %>%
  mutate(Hour = sapply(Time, get_hour)) %>%
  group_by(PdDistrict, DayOfWeek, Hour) %>% 
  summarize(count = n()) %>%
  group_by(PdDistrict) %>%
  mutate(norm = count/sum(count))
df_arrest_time_district$DayOfWeek <- factor(df_arrest_time_district$DayOfWeek, level = rev(dow_format))
df_arrest_time_district$Hour <- factor(df_arrest_time_district$Hour, level = 0:23, label = hour_format)
datatable(df_arrest_time_district, options = list(pageLength = 10,scrollX = '400px'))
plot_district <- ggplot(df_arrest_time_district, aes(x = Hour, y = DayOfWeek, fill = norm)) +
  geom_tile() +
  # fte_theme() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.6, size = 4)) +
  labs(x = "Hour of Arrest (Local Time)", y = "Day of Week of Arrest", title = "Police Arrests in San Francisco by Time of Arrest, Normalized by Station (2003-2018)") +
  scale_fill_gradient(low = "white", high = "#8E44AD") +
  facet_wrap(~ PdDistrict, nrow = 5)
plot_district

Factor by Month

If crime is tied to activities, the period at which activies end may impact.

df_arrest_time_month <- df_arrest %>%
  mutate(Month = format(as.Date(Date, "%m/%d/%Y"), "%B"), Hour = sapply(Time, get_hour)) %>%
  group_by(Month, DayOfWeek, Hour) %>% 
  summarize(count = n()) %>%
  group_by(Month) %>%
  mutate(norm = count/sum(count))
df_arrest_time_month$DayOfWeek <- factor(df_arrest_time_month$DayOfWeek, level = rev(dow_format))
df_arrest_time_month$Hour <- factor(df_arrest_time_month$Hour, level = 0:23, label = hour_format)
# Set order of month facets by chronological order instead of alphabetical
df_arrest_time_month$Month <- factor(df_arrest_time_month$Month,
                                     level = c("January","February","March","April","May","June","July","August","September","October","November","December"))
plot_monthly <- ggplot(df_arrest_time_month, aes(x = Hour, y = DayOfWeek, fill = norm)) +
  geom_tile() +
  # fte_theme() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.6, size = 4)) +
  labs(x = "Hour of Arrest (Local Time)", y = "Day of Week of Arrest", title = "Police Arrests in San Francisco from 2007 – 2016 by Time of Arrest, Normalized by Month") +
  scale_fill_gradient(low = "white", high = "#E74C3C") +
  facet_wrap(~ Month, nrow = 4)
plot_monthly

Factor By Year

Perhaps things changed overtime?

df_arrest_time_year <- df_arrest %>%
  mutate(Year = format(as.Date(Date, "%m/%d/%Y"), "%Y"), Hour = sapply(Time, get_hour)) %>%
  group_by(Year, DayOfWeek, Hour) %>% 
  summarize(count = n()) %>%
  group_by(Year) %>%
  mutate(norm = count/sum(count))
df_arrest_time_year$DayOfWeek <- factor(df_arrest_time_year$DayOfWeek, level = rev(dow_format))
df_arrest_time_year$Hour <- factor(df_arrest_time_year$Hour, level = 0:23, label = hour_format)
plot_yearly <- ggplot(df_arrest_time_year, aes(x = Hour, y = DayOfWeek, fill = norm)) +
  geom_tile() +
  # fte_theme() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.6, size = 4)) +
  labs(x = "Hour of Arrest (Local Time)", y = "Day of Week of Arrest", title = "Police Arrests in San Francisco from 2007 – 2016 by Time of Arrest, Normalized by Year") +
  scale_fill_gradient(low = "white", high = "#E67E22") +
  facet_wrap(~ Year, nrow = 6)
plot_yearly

LS0tCnRpdGxlOiAiQ3JpbWUgQW5hbHlzaXMgVXNpbmcgUiBhbmQgQXJjR0lTIgphdXRob3I6IERyLiBRaXVzaGVuZyBXdQpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgSW50cm9kdWN0aW9uCiMjIyBPYmplY3RpdmVzCiogKipWaXN1YWxpemluZyBzcGF0aWFsIGFuZCB0ZW1wb3JhbCB0cmVuZHMgb2YgY3JpbWluYWwgYWN0aXZpdHkqKgoqICoqQW5hbHl6aW5nIGZhY3RvcnMgdGhhdCBtYXkgYWZmZWN0IHVubGF3ZnVsIGJlaGF2aW9yKioKCiMjIyBTdHVkeSBBcmVhCiogU2FuIEZyYW5jaXNjbywgQ2FsaWZvcm5pYQoqIFtQb2xpY2UgRGVwYXJ0bWVudCBJbmNpZGVudHMgRGF0YSAyMDAzLTIwMThdKGh0dHBzOi8vZ29vLmdsL1JCNDRCTSkgKERpcmVjdCBkb3dubG9hZCBbIGxpbmtdKGh0dHBzOi8vZGF0YS5zZmdvdi5vcmcvYXBpL3ZpZXdzL3RtbmYteXZyeS9yb3dzLmNzdj9hY2Nlc3NUeXBlPURPV05MT0FEKSkgKDQzNSBNQikKCiMjIFNvZnR3YXJlIE5lZWRlZAojIyMgRG93bmxvYWQgUiBhbmQgUlN0dWRpbwpGaXJzdCwgeW91J2xsIGRvd25sb2FkIGFuZCBzZXQgdXAgUiBhbmQgUlN0dWRpbywgYSBmcmVlIGludGVncmF0ZWQgZGV2ZWxvcG1lbnQgZW52aXJvbm1lbnQgZm9yIFIuIFJTdHVkaW8gaGVscHMgeW91CndvcmsgaW4gUiBieSBwcm92aWRpbmcgYSBjb2RpbmcgcGxhdGZvcm0gd2l0aCBhY2Nlc3MgdG8gQ1JBTiwgdGhlIENvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmssIHdoaWNoIGNvbnRhaW5zCnRob3VzYW5kcyBvZiBSIGxpYnJhcmllcywgYSBidWlsdC1pbiB2aWV3ZXIgZm9yIGNoYXJ0cyBhbmQgZ3JhcGhzLCBhbmQgb3RoZXIgdXNlZnVsIGZlYXR1cmVzLgoKKiAgSWYgbmVjZXNzYXJ5LCBkb3dubG9hZCBbUiAzLjUuMCBvciBsYXRlcl0oaHR0cHM6Ly9jbG91ZC5yLXByb2plY3Qub3JnLykuIEFjY2VwdCBhbGwgZGVmYXVsdHMgaW4gdGhlIGluc3RhbGxhdGlvbiB3aXphcmQuCgoqICBJZiBuZWNlc3NhcnksIGRvd25sb2FkIFtSU3R1ZGlvIERlc2t0b3BdKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vZG93bmxvYWQpLiBBY2NlcHQgYWxsIGRlZmF1bHRzIGluIHRoZSBpbnN0YWxsYXRpb24gd2l6YXJkLgoKIyMjIEluc3RhbGwgUiBsaWJyYXJpZXMKYGBge3IgaW5zdGFsbCBsaWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmlmICghcmVxdWlyZShyZWFkcikpIGluc3RhbGwucGFja2FnZXMoInJlYWRyIikKaWYgKCFyZXF1aXJlKGRwbHlyKSkgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppZiAoIXJlcXVpcmUoRFQpKSBpbnN0YWxsLnBhY2thZ2VzKCJEVCIpCmlmICghcmVxdWlyZShnZ3JlcGVsKSkgaW5zdGFsbC5wYWNrYWdlcygiZ2dyZXBlbCIpCmlmICghcmVxdWlyZShsZWFmbGV0KSkgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIpCmBgYAoKIyMgRGF0YSBQcmVwcm9jZXNzaW5nCiMjIyBSZWFkIHRoZSBkYXRhCkxvYWQgdGhlIGRhdGEgdXNpbmcgcmVhZHIgYW5kIHJlYWRfY3N2KCkuCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkocmVhZHIpCnBhdGggPC0gIi9wYXRoL3RvL2NyaW1lL2RhdGEvU0ZfQ3JpbWVfMjAwM18yMDE4LmNzdiIKZGYgPC0gcmVhZF9jc3YocGF0aCkKYGBgCgojIyMgRGlzcGxheSBEYXRhCkRpc3BsYXkgdGhlIGRhdGEgdXNpbmcgRFQgYW5kIGRhdGF0YWJsZSgpLgpgYGB7cn0KbGlicmFyeShEVCkKZGZfc3ViIDwtIGRmWzE6MTAwLF0gICMgZGlzcGxheSB0aGUgZmlyc3QgMTAwIHJvd3MKZGZfc3ViJFRpbWUgPC0gYXMuY2hhcmFjdGVyKGRmX3N1YiRUaW1lKSAKZGF0YXRhYmxlKGRmX3N1Yiwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDUsc2Nyb2xsWCA9ICc0MDBweCcpKQoKc3ByaW50ZigiTnVtYmVyIG9mIFJvd3MgaW4gRGF0YWZyYW1lOiAlcyIsIGZvcm1hdChucm93KGRmKSxiaWcubWFyayA9ICIsIikpCmBgYAoKIyMjIFByZXByb2Nlc3MgRGF0YSAgClRoZSBBbGwtQ2FwcyB0ZXh0IGlzIGRpZmZpY3VsdCB0byByZWFkLiBMZXQncyBmb3JjZSB0aGUgdGV4dCBpbiB0aGUgYXBwcm9wcmlhdGUgY29sdW1ucyBpbnRvIHByb3BlciBjYXNlLiAKCmBgYHtyfQojIHN0cihkZikKcHJvcGVyX2Nhc2UgPC0gZnVuY3Rpb24oeCkgewogIHJldHVybihnc3ViKCJcXGIoW0EtWl0pKFtBLVpdKykiLCAiXFxVXFwxXFxMXFwyIiAsIHgsIHBlcmwgPSBUUlVFKSkKfQoKbGlicmFyeShkcGx5cikKZGYgPC0gZGYgJT4lIG11dGF0ZShDYXRlZ29yeSA9IHByb3Blcl9jYXNlKENhdGVnb3J5KSwKICAgICAgICAgICAgICAgICAgICBEZXNjcmlwdCA9IHByb3Blcl9jYXNlKERlc2NyaXB0KSwKICAgICAgICAgICAgICAgICAgICBQZERpc3RyaWN0ID0gcHJvcGVyX2Nhc2UoUGREaXN0cmljdCksCiAgICAgICAgICAgICAgICAgICAgUmVzb2x1dGlvbiA9IHByb3Blcl9jYXNlKFJlc29sdXRpb24pLAogICAgICAgICAgICAgICAgICAgIFRpbWUgPSBhcy5jaGFyYWN0ZXIoVGltZSkpCmRmX3N1YiA8LSBkZlsxOjEwMCxdICAjIGRpc3BsYXkgdGhlIGZpcnN0IDEwMCByb3dzCmRhdGF0YWJsZShkZl9zdWIsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1LHNjcm9sbFggPSAnNDAwcHgnKSkKYGBgCgoKIyMgVmlzdWFsaXplIERhdGEKIyMjIENyaW1lIGFjcm9zcyBzcGFjZQpEaXNwbGF5IGNyaW1lIGluY2lkZW50IGxvY2F0aW9ucyBvbiB0aGUgbWFwIHVzaW5nIGxlYWZsZXQuIENsaWNrIGljb25zIG9uIHRoZSBtYXAgdG8gc2hvdyBpbmNpZGVudCBkZXRhaWxzLgpgYGB7cn0KbGlicmFyeShsZWFmbGV0KQoKZGF0YSA8LSBkZlsxOjEwMDAwLF0gIyBkaXNwbGF5IHRoZSBmaXJzdCAxMCwwMDAgcm93cwpkYXRhJHBvcHVwIDwtIHBhc3RlKCI8Yj5JbmNpZGVudCAjOiA8L2I+IiwgZGF0YSRJbmNpZG50TnVtLCAiPGJyPiIsICI8Yj5DYXRlZ29yeTogPC9iPiIsIGRhdGEkQ2F0ZWdvcnksCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+RGVzY3JpcHRpb246IDwvYj4iLCBkYXRhJERlc2NyaXB0LAogICAgICAgICAgICAgICAgICAgICI8YnI+IiwgIjxiPkRheSBvZiB3ZWVrOiA8L2I+IiwgZGF0YSREYXlPZldlZWssCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+RGF0ZTogPC9iPiIsIGRhdGEkRGF0ZSwKICAgICAgICAgICAgICAgICAgICAiPGJyPiIsICI8Yj5UaW1lOiA8L2I+IiwgZGF0YSRUaW1lLAogICAgICAgICAgICAgICAgICAgICI8YnI+IiwgIjxiPlBEIGRpc3RyaWN0OiA8L2I+IiwgZGF0YSRQZERpc3RyaWN0LAogICAgICAgICAgICAgICAgICAgICI8YnI+IiwgIjxiPlJlc29sdXRpb246IDwvYj4iLCBkYXRhJFJlc29sdXRpb24sCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+QWRkcmVzczogPC9iPiIsIGRhdGEkQWRkcmVzcywKICAgICAgICAgICAgICAgICAgICAiPGJyPiIsICI8Yj5Mb25naXR1ZGU6IDwvYj4iLCBkYXRhJFgsCiAgICAgICAgICAgICAgICAgICAgIjxicj4iLCAiPGI+TGF0aXR1ZGU6IDwvYj4iLCBkYXRhJFkpCgpsZWFmbGV0KGRhdGEsIHdpZHRoID0gIjEwMCUiKSAlPiUgYWRkVGlsZXMoKSAlPiUKICBhZGRUaWxlcyhncm91cCA9ICJPU00gKGRlZmF1bHQpIikgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlciA9ICJFc3JpLldvcmxkU3RyZWV0TWFwIixncm91cCA9ICJXb3JsZCBTdHJlZXRNYXAiKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gIkVzcmkuV29ybGRJbWFnZXJ5Iixncm91cCA9ICJXb3JsZCBJbWFnZXJ5IikgJT4lCiAgIyBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gIk5BU0FHSUJTLlZpaXJzRWFydGhBdE5pZ2h0MjAxMiIsZ3JvdXAgPSAiTmlnaHR0aW1lIEltYWdlcnkiKSAlPiUKICBhZGRNYXJrZXJzKGxuZyA9IH5YLCBsYXQgPSB+WSwgcG9wdXAgPSBkYXRhJHBvcHVwLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCkpICU+JQogIGFkZExheWVyc0NvbnRyb2woCiAgICBiYXNlR3JvdXBzID0gYygiT1NNIChkZWZhdWx0KSIsIldvcmxkIFN0cmVldE1hcCIsICJXb3JsZCBJbWFnZXJ5IiksCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpCiAgKQpgYGAKCgojIyMgQ3JpbWUgT3ZlciBUaW1lCmBgYHtyLCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZHBseXIpCgpkZl9jcmltZV9kYWlseSA8LSBkZiAlPiUKICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgIiVtLyVkLyVZIikpICU+JQogIGdyb3VwX2J5KERhdGUpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShEYXRlKQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKcGxvdF9kYWlseV9jcmltZXMgPC0gZ2dwbG90KGRmX2NyaW1lX2RhaWx5LCBhZXMoeCA9IERhdGUsIHkgPSBjb3VudCkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiI0YyQ0EyNyIsIHNpemUgPSAwLjEpICsKICBnZW9tX3Ntb290aChjb2xvciA9ICIjMUExQTFBIikgKwogICMgZnRlX3RoZW1lKCkgKwogIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMSB5ZWFyIiksIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWSIpKSArCiAgbGFicyh4ID0gIkRhdGUgb2YgQ3JpbWUiLCB5ID0gIk51bWJlciBvZiBDcmltZXMiLCB0aXRsZSA9ICJEYWlseSBDcmltZXMgaW4gU2FuIEZyYW5jaXNjbyAoMjAwM+KAkzIwMTgpIikKcGxvdF9kYWlseV9jcmltZXMKYGBgCgoKIyMgQWdncmVnYXRlIERhdGEKU3VtbWFyaXplIHRoZSBkYXRhIGJ5IGluY2lkZW50IGNhdGVnb3J5LgpgYGB7cn0KZGZfY2F0ZWdvcnkgPC0gc29ydCh0YWJsZShkZiRDYXRlZ29yeSksZGVjcmVhc2luZyA9IFRSVUUpCmRmX2NhdGVnb3J5IDwtIGRhdGEuZnJhbWUoZGZfY2F0ZWdvcnlbZGZfY2F0ZWdvcnkgPiAxMDAwMF0pCmNvbG5hbWVzKGRmX2NhdGVnb3J5KSA8LSBjKCJDYXRlZ29yeSIsICJGcmVxdWVuY3kiKQpkZl9jYXRlZ29yeSRQZXJjZW50YWdlIDwtIGRmX2NhdGVnb3J5JEZyZXF1ZW5jeSAvIHN1bShkZl9jYXRlZ29yeSRGcmVxdWVuY3kpCmRhdGF0YWJsZShkZl9jYXRlZ29yeSwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9ICc0MDBweCcpKQpgYGAKCgpDcmVhdGUgYSBiYXIgcGxvdCBiYXNlZCBvbiB0aGUgaW5jaWRlbnQgY2F0ZWdvcnkuCmBgYHtyIGZpZy53aWR0aD0xMH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmJwPC1nZ3Bsb3QoZGZfY2F0ZWdvcnksIGFlcyh4PUNhdGVnb3J5LCB5PUZyZXF1ZW5jeSwgZmlsbD1DYXRlZ29yeSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkgKyBnZW9tX3RleHRfcmVwZWwoZGF0YT1kZl9jYXRlZ29yeSwgYWVzKGxhYmVsPUNhdGVnb3J5KSkKYnAKYGBgCgpDcmVhdGUgYSBwaWUgY2hhcnQgYmFzZWQgb24gdGhlIGluY2lkZW50IGNhdGVnb3J5LgpgYGB7ciBmaWcud2lkdGg9MTB9CmJwPC1nZ3Bsb3QoZGZfY2F0ZWdvcnksIGFlcyh4PSIiLCB5PVBlcmNlbnRhZ2UsIGZpbGw9Q2F0ZWdvcnkpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgCnBpZSA8LSBicCArIGNvb3JkX3BvbGFyKCJ5IikgCnBpZQpgYGAKCgojIyBUZW1wb3JhbCBUcmVuZHMgCgojIyMgVGhlZnQgT3ZlciBUaW1lCkNyZWF0ZSBhIGNoYXJ0IG9mIGNyaW1lcyAoTGFyY2VueS9UaGVmdCkgb3ZlciB0aW1lLgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTEwfQpkZl90aGVmdCA8LSBkZiAlPiUgZmlsdGVyKGdyZXBsKCJMYXJjZW55L1RoZWZ0IiwgQ2F0ZWdvcnkpKQoKZGZfdGhlZnRfZGFpbHkgPC0gZGZfdGhlZnQgJT4lCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsICIlbS8lZC8lWSIpKSAlPiUKICBncm91cF9ieShEYXRlKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JQogIGFycmFuZ2UoRGF0ZSkKCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShzY2FsZXMpCnBsb3RfZGFpbHlfdGhlZnQgPC0gZ2dwbG90KGRmX3RoZWZ0X2RhaWx5LCBhZXMoeCA9IERhdGUsIHkgPSBjb3VudCkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiI0YyQ0EyNyIsIHNpemUgPSAwLjEpICsKICBnZW9tX3Ntb290aChjb2xvciA9ICIjMUExQTFBIikgKwogICMgZnRlX3RoZW1lKCkgKwogIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMSB5ZWFyIiksIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWSIpKSArCiAgbGFicyh4ID0gIkRhdGUgb2YgVGhlZnQiLCB5ID0gIk51bWJlciBvZiBUaGVmdHMiLCB0aXRsZSA9ICJEYWlseSBUaGVmdHMgaW4gU2FuIEZyYW5jaXNjbyAoMjAwM+KAkzIwMTgpIikKcGxvdF9kYWlseV90aGVmdApgYGAKCiMjIyBUaGVmdCBUaW1lIEhlYXRtYXAKQWdncmVnYXRlIGNvdW50cyBvZiB0aGVmdHMgYnkgRGF5LW9mLVdlZWsgYW5kIFRpbWUgdG8gY3JlYXRlIGhlYXQgbWFwLiBGb3J0dW5hdGVseSwgdGhlIERheS1PZi1XZWVrIHBhcnQgaXMgcHJlLWRlcml2ZWQsIGJ1dCBIb3VyIGlzIHNsaWdodGx5IGhhcmRlci4KYGBge3J9CmdldF9ob3VyIDwtIGZ1bmN0aW9uKHgpIHsKICByZXR1cm4oYXMubnVtZXJpYyhzdHJzcGxpdCh4LCI6IilbWzFdXVsxXSkpCn0KCmRmX3RoZWZ0X3RpbWUgPC0gZGZfdGhlZnQgJT4lCiAgbXV0YXRlKEhvdXIgPSBzYXBwbHkoVGltZSwgZ2V0X2hvdXIpKSAlPiUKICBncm91cF9ieShEYXlPZldlZWssIEhvdXIpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkKIyBkZl90aGVmdF90aW1lICU+JSBoZWFkKDEwKQpkYXRhdGFibGUoZGZfdGhlZnRfdGltZSwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9ICc0MDBweCcpKQpgYGAKClJlb3JkZXIgYW5kIGZvcm1hdCBGYWN0b3JzLgpgYGB7cn0KZG93X2Zvcm1hdCA8LSBjKCJTdW5kYXkiLCJNb25kYXkiLCJUdWVzZGF5IiwiV2VkbmVzZGF5IiwiVGh1cnNkYXkiLCJGcmlkYXkiLCJTYXR1cmRheSIpCmhvdXJfZm9ybWF0IDwtIGMocGFzdGUoYygxMiwxOjExKSwiQU0iKSwgcGFzdGUoYygxMiwxOjExKSwiUE0iKSkKCmRmX3RoZWZ0X3RpbWUkRGF5T2ZXZWVrIDwtIGZhY3RvcihkZl90aGVmdF90aW1lJERheU9mV2VlaywgbGV2ZWwgPSByZXYoZG93X2Zvcm1hdCkpCmRmX3RoZWZ0X3RpbWUkSG91ciA8LSBmYWN0b3IoZGZfdGhlZnRfdGltZSRIb3VyLCBsZXZlbCA9IDA6MjMsIGxhYmVsID0gaG91cl9mb3JtYXQpCgojIGRmX3RoZWZ0X3RpbWUgJT4lIGhlYWQoMTApCmRhdGF0YWJsZShkZl90aGVmdF90aW1lLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gJzQwMHB4JykpCmBgYAoKQ3JlYXRlIFRpbWUgSGVhdG1hcApgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTEwfQpwbG90X3RoZWZ0X2hlYXRtYXAgPC0gZ2dwbG90KGRmX3RoZWZ0X3RpbWUsIGFlcyh4ID0gSG91ciwgeSA9IERheU9mV2VlaywgZmlsbCA9IGNvdW50KSkgKwogIGdlb21fdGlsZSgpICsKICAjIGZ0ZV90aGVtZSgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC4yNSwgImNtIiksIGxlZ2VuZC5tYXJnaW4gPSB1bml0KC0wLjUsImNtIiksIHBhbmVsLm1hcmdpbiA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoeCA9ICJIb3VyIG9mIFRoZWZ0IChMb2NhbCBUaW1lKSIsIHkgPSAiRGF5IG9mIFdlZWsgb2YgVGhlZnQiLCB0aXRsZSA9ICJOdW1iZXIgb2YgVGhlZnRzIGluIFNhbiBGcmFuY2lzY28gYnkgVGltZSBvZiBUaGVmdCAoMjAwMy0yMDE4KSIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAiIzI3QUU2MCIsIGxhYmVscyA9IGNvbW1hKQpwbG90X3RoZWZ0X2hlYXRtYXAKYGBgCgpIbW0sIHdoeSBpcyB0aGVyZSBhIHN1cmdlIGF0IDYtN1BNIG9uIHdlZWtkYXlzPyAKCiMjIyBBcnJlc3QgT3ZlciBUaW1lCkNyZWF0ZSBhIGNoYXJ0IG9mIGFycmVzdHMgb3ZlciB0aW1lLgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTEwfQpkZl9hcnJlc3QgPC0gZGYgJT4lIGZpbHRlcihncmVwbCgiQXJyZXN0IiwgUmVzb2x1dGlvbikpCgpkZl9hcnJlc3RfZGFpbHkgPC0gZGZfYXJyZXN0ICU+JQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCAiJW0vJWQvJVkiKSkgJT4lCiAgZ3JvdXBfYnkoRGF0ZSkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUKICBhcnJhbmdlKERhdGUpCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhbGVzKQpwbG90X2RhaWx5X2FycmVzdHMgPC0gZ2dwbG90KGRmX2FycmVzdF9kYWlseSwgYWVzKHggPSBEYXRlLCB5ID0gY291bnQpKSArCiAgZ2VvbV9saW5lKGNvbG9yID0gIiNGMkNBMjciLCBzaXplID0gMC4xKSArCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiIzFBMUExQSIpICsKICAjIGZ0ZV90aGVtZSgpICsKICBzY2FsZV94X2RhdGUoYnJlYWtzID0gZGF0ZV9icmVha3MoIjEgeWVhciIpLCBsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVkiKSkgKwogIGxhYnMoeCA9ICJEYXRlIG9mIEFycmVzdCIsIHkgPSAiIyBvZiBQb2xpY2UgQXJyZXN0cyIsIHRpdGxlID0gIkRhaWx5IFBvbGljZSBBcnJlc3RzIGluIFNhbiBGcmFuY2lzY28gKDIwMDPigJMyMDE4KSIpCnBsb3RfZGFpbHlfYXJyZXN0cwpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdldF9ob3VyIDwtIGZ1bmN0aW9uKHgpIHsKICByZXR1cm4oYXMubnVtZXJpYyhzdHJzcGxpdCh4LCI6IilbWzFdXVsxXSkpCn0KCmRmX2FycmVzdF90aW1lIDwtIGRmX2FycmVzdCAlPiUKICBtdXRhdGUoSG91ciA9IHNhcHBseShUaW1lLCBnZXRfaG91cikpICU+JQogIGdyb3VwX2J5KERheU9mV2VlaywgSG91cikgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKQoKZG93X2Zvcm1hdCA8LSBjKCJTdW5kYXkiLCJNb25kYXkiLCJUdWVzZGF5IiwiV2VkbmVzZGF5IiwiVGh1cnNkYXkiLCJGcmlkYXkiLCJTYXR1cmRheSIpCmhvdXJfZm9ybWF0IDwtIGMocGFzdGUoYygxMiwxOjExKSwiQU0iKSwgcGFzdGUoYygxMiwxOjExKSwiUE0iKSkKCmRmX2FycmVzdF90aW1lJERheU9mV2VlayA8LSBmYWN0b3IoZGZfYXJyZXN0X3RpbWUkRGF5T2ZXZWVrLCBsZXZlbCA9IHJldihkb3dfZm9ybWF0KSkKZGZfYXJyZXN0X3RpbWUkSG91ciA8LSBmYWN0b3IoZGZfYXJyZXN0X3RpbWUkSG91ciwgbGV2ZWwgPSAwOjIzLCBsYWJlbCA9IGhvdXJfZm9ybWF0KQoKcGxvdF90aW1lX2FycmVzdCA8LSBnZ3Bsb3QoZGZfYXJyZXN0X3RpbWUsIGFlcyh4ID0gSG91ciwgeSA9IERheU9mV2VlaywgZmlsbCA9IGNvdW50KSkgKwogIGdlb21fdGlsZSgpICsKICAjIGZ0ZV90aGVtZSgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC4yNSwgImNtIiksIGxlZ2VuZC5tYXJnaW4gPSB1bml0KC0wLjUsImNtIiksIHBhbmVsLm1hcmdpbiA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoeCA9ICJIb3VyIG9mIEFycmVzdCAoTG9jYWwgVGltZSkiLCB5ID0gIkRheSBvZiBXZWVrIG9mIEFycmVzdCIsIHRpdGxlID0gIk51bWJlciBvZiBQb2xpY2UgQXJyZXN0cyBpbiBTYW4gRnJhbmNpc2NvIGJ5IFRpbWUgb2YgQXJyZXN0ICgyMDAz4oCTMjAxOCkiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiMyN0FFNjAiLCBsYWJlbHMgPSBjb21tYSkKcGxvdF90aW1lX2FycmVzdApgYGAKSG1tLCB3aHkgaXMgdGhlcmUgYSBzdXJnZSBvbiBXZWRuZXNkYXkgYWZ0ZXJub29uLCBhbmQgYXQgNC01UE0gb24gYWxsIGRheXM/IExldCdzIGxvb2sgYXQgc3ViZ3JvdXBzIHRvIHZlcmlmeSB0aGVyZSBpc24ndCBhIGxhdGVudCBmYWN0b3IuCgojIyBDb3JyZWxhdGlvbiBBbmFseXNpcwoKIyMjIEZhY3RvciBieSBDcmltZSBDYXRlZ29yeQpDZXJ0YWluIHR5cGVzIG9mIGNyaW1lIG1heSBiZSBtb3JlIHRpbWUgZGVwZW5kZW50LiAoZS5nLiwgbW9yZSB0cmFmZmljIHZpb2xhdGlvbnMgd2hlbiBwZW9wbGUgbGVhdmUgd29yaykKYGBge3J9CmRmX3RvcF9jcmltZXMgPC0gZGZfYXJyZXN0ICU+JQogIGdyb3VwX2J5KENhdGVnb3J5KSAlPiUgCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnQpKQoKZGF0YXRhYmxlKGRmX3RvcF9jcmltZXMsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCxzY3JvbGxYID0gJzQwMHB4JykpCmBgYAoKYGBge3J9CmRmX2FycmVzdF90aW1lX2NyaW1lIDwtIGRmX2FycmVzdCAlPiUKICBmaWx0ZXIoQ2F0ZWdvcnkgJWluJSBkZl90b3BfY3JpbWVzJENhdGVnb3J5WzI6MTldKSAlPiUKICBtdXRhdGUoSG91ciA9IHNhcHBseShUaW1lLCBnZXRfaG91cikpICU+JQogIGdyb3VwX2J5KENhdGVnb3J5LCBEYXlPZldlZWssIEhvdXIpICU+JSAKICBzdW1tYXJpemUoY291bnQgPSBuKCkpCgpkZl9hcnJlc3RfdGltZV9jcmltZSREYXlPZldlZWsgPC0gZmFjdG9yKGRmX2FycmVzdF90aW1lX2NyaW1lJERheU9mV2VlaywgbGV2ZWwgPSByZXYoZG93X2Zvcm1hdCkpCmRmX2FycmVzdF90aW1lX2NyaW1lJEhvdXIgPC0gZmFjdG9yKGRmX2FycmVzdF90aW1lX2NyaW1lJEhvdXIsIGxldmVsID0gMDoyMywgbGFiZWwgPSBob3VyX2Zvcm1hdCkKCmRhdGF0YWJsZShkZl9hcnJlc3RfdGltZV9jcmltZSwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLHNjcm9sbFggPSAnNDAwcHgnKSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90X251bV9hcnJlc3RzIDwtIGdncGxvdChkZl9hcnJlc3RfdGltZV9jcmltZSwgYWVzKHggPSBIb3VyLCB5ID0gRGF5T2ZXZWVrLCBmaWxsID0gY291bnQpKSArCiAgZ2VvbV90aWxlKCkgKwogICMgZnRlX3RoZW1lKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC42LCBzaXplID0gNCkpICsKICBsYWJzKHggPSAiSG91ciBvZiBBcnJlc3QgKExvY2FsIFRpbWUpIiwgeSA9ICJEYXkgb2YgV2VlayBvZiBBcnJlc3QiLCB0aXRsZSA9ICJOdW1iZXIgb2YgUG9saWNlIEFycmVzdHMgaW4gU2FuIEZyYW5jaXNjbyBieSBDYXRlZ29yeSBhbmQgVGltZSBvZiBBcnJlc3QgKDIwMDMtMjAxOCkiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiMyOTgwQjkiKSArCiAgZmFjZXRfd3JhcCh+IENhdGVnb3J5LCBucm93ID0gNikKcGxvdF9udW1fYXJyZXN0cwpgYGAKCkdvb2QsIGJ1dCB0aGUgZ3JhZGllbnRzIGFyZW4ndCBoZWxwZnVsIGJlY2F1c2UgdGhleSBhcmUgbm90IG5vcm1hbGl6ZWQuIFdlIG5lZWQgdG8gbm9ybWFsaXplIHRoZSByYW5nZSBvbiBlYWNoIGZhY2V0LiAodW5mb3J0dW5hdGVseSwgdGhpcyBtYWtlcyB0aGUgdmFsdWUgb2YgdGhlIGdyYWRpZW50IHVuaGVscGZ1bCkKCmBgYHtyfQpkZl9hcnJlc3RfdGltZV9jcmltZSA8LSBkZl9hcnJlc3RfdGltZV9jcmltZSAlPiUKICBncm91cF9ieShDYXRlZ29yeSkgJT4lCiAgbXV0YXRlKG5vcm0gPSBjb3VudC9zdW0oY291bnQpKQoKZGF0YXRhYmxlKGRmX2FycmVzdF90aW1lX2NyaW1lLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsc2Nyb2xsWCA9ICc0MDBweCcpKQoKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90IDwtIGdncGxvdChkZl9hcnJlc3RfdGltZV9jcmltZSwgYWVzKHggPSBIb3VyLCB5ID0gRGF5T2ZXZWVrLCBmaWxsID0gbm9ybSkpICsKICBnZW9tX3RpbGUoKSArCiAgIyBmdGVfdGhlbWUoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjYsIHNpemUgPSA0KSkgKwogIGxhYnMoeCA9ICJIb3VyIG9mIEFycmVzdCAoTG9jYWwgVGltZSkiLCB5ID0gIkRheSBvZiBXZWVrIG9mIEFycmVzdCIsIHRpdGxlID0gIlBvbGljZSBBcnJlc3RzIGluIFNhbiBGcmFuY2lzY28gYnkgVGltZSBvZiBBcnJlc3QsIE5vcm1hbGl6ZWQgYnkgVHlwZSBvZiBDcmltZSAoMjAwMy0yMDE4KSIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAiIzI5ODBCOSIpICsKICBmYWNldF93cmFwKH4gQ2F0ZWdvcnksIG5yb3cgPSA2KQpwbG90CmBgYAoKIyMjIEZhY3RvciBieSBQb2xpY2UgRGlzdHJpY3QKU2FtZSBhcyBhYm92ZSwgYnV0IHdpdGggYSBkaWZmZXJlbnQgZmFjZXQuCgpgYGB7cn0KZGZfYXJyZXN0X3RpbWVfZGlzdHJpY3QgPC0gZGZfYXJyZXN0ICU+JQogIG11dGF0ZShIb3VyID0gc2FwcGx5KFRpbWUsIGdldF9ob3VyKSkgJT4lCiAgZ3JvdXBfYnkoUGREaXN0cmljdCwgRGF5T2ZXZWVrLCBIb3VyKSAlPiUgCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUKICBncm91cF9ieShQZERpc3RyaWN0KSAlPiUKICBtdXRhdGUobm9ybSA9IGNvdW50L3N1bShjb3VudCkpCgpkZl9hcnJlc3RfdGltZV9kaXN0cmljdCREYXlPZldlZWsgPC0gZmFjdG9yKGRmX2FycmVzdF90aW1lX2Rpc3RyaWN0JERheU9mV2VlaywgbGV2ZWwgPSByZXYoZG93X2Zvcm1hdCkpCmRmX2FycmVzdF90aW1lX2Rpc3RyaWN0JEhvdXIgPC0gZmFjdG9yKGRmX2FycmVzdF90aW1lX2Rpc3RyaWN0JEhvdXIsIGxldmVsID0gMDoyMywgbGFiZWwgPSBob3VyX2Zvcm1hdCkKCmRhdGF0YWJsZShkZl9hcnJlc3RfdGltZV9kaXN0cmljdCwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLHNjcm9sbFggPSAnNDAwcHgnKSkKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdF9kaXN0cmljdCA8LSBnZ3Bsb3QoZGZfYXJyZXN0X3RpbWVfZGlzdHJpY3QsIGFlcyh4ID0gSG91ciwgeSA9IERheU9mV2VlaywgZmlsbCA9IG5vcm0pKSArCiAgZ2VvbV90aWxlKCkgKwogICMgZnRlX3RoZW1lKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC42LCBzaXplID0gNCkpICsKICBsYWJzKHggPSAiSG91ciBvZiBBcnJlc3QgKExvY2FsIFRpbWUpIiwgeSA9ICJEYXkgb2YgV2VlayBvZiBBcnJlc3QiLCB0aXRsZSA9ICJQb2xpY2UgQXJyZXN0cyBpbiBTYW4gRnJhbmNpc2NvIGJ5IFRpbWUgb2YgQXJyZXN0LCBOb3JtYWxpemVkIGJ5IFN0YXRpb24gKDIwMDMtMjAxOCkiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiM4RTQ0QUQiKSArCiAgZmFjZXRfd3JhcCh+IFBkRGlzdHJpY3QsIG5yb3cgPSA1KQpwbG90X2Rpc3RyaWN0CmBgYAoKIyMjIEZhY3RvciBieSBNb250aAoKSWYgY3JpbWUgaXMgdGllZCB0byBhY3Rpdml0aWVzLCB0aGUgcGVyaW9kIGF0IHdoaWNoIGFjdGl2aWVzIGVuZCBtYXkgaW1wYWN0LgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRmX2FycmVzdF90aW1lX21vbnRoIDwtIGRmX2FycmVzdCAlPiUKICBtdXRhdGUoTW9udGggPSBmb3JtYXQoYXMuRGF0ZShEYXRlLCAiJW0vJWQvJVkiKSwgIiVCIiksIEhvdXIgPSBzYXBwbHkoVGltZSwgZ2V0X2hvdXIpKSAlPiUKICBncm91cF9ieShNb250aCwgRGF5T2ZXZWVrLCBIb3VyKSAlPiUgCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUKICBncm91cF9ieShNb250aCkgJT4lCiAgbXV0YXRlKG5vcm0gPSBjb3VudC9zdW0oY291bnQpKQoKZGZfYXJyZXN0X3RpbWVfbW9udGgkRGF5T2ZXZWVrIDwtIGZhY3RvcihkZl9hcnJlc3RfdGltZV9tb250aCREYXlPZldlZWssIGxldmVsID0gcmV2KGRvd19mb3JtYXQpKQpkZl9hcnJlc3RfdGltZV9tb250aCRIb3VyIDwtIGZhY3RvcihkZl9hcnJlc3RfdGltZV9tb250aCRIb3VyLCBsZXZlbCA9IDA6MjMsIGxhYmVsID0gaG91cl9mb3JtYXQpCgojIFNldCBvcmRlciBvZiBtb250aCBmYWNldHMgYnkgY2hyb25vbG9naWNhbCBvcmRlciBpbnN0ZWFkIG9mIGFscGhhYmV0aWNhbApkZl9hcnJlc3RfdGltZV9tb250aCRNb250aCA8LSBmYWN0b3IoZGZfYXJyZXN0X3RpbWVfbW9udGgkTW9udGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbCA9IGMoIkphbnVhcnkiLCJGZWJydWFyeSIsIk1hcmNoIiwiQXByaWwiLCJNYXkiLCJKdW5lIiwiSnVseSIsIkF1Z3VzdCIsIlNlcHRlbWJlciIsIk9jdG9iZXIiLCJOb3ZlbWJlciIsIkRlY2VtYmVyIikpCgpwbG90X21vbnRobHkgPC0gZ2dwbG90KGRmX2FycmVzdF90aW1lX21vbnRoLCBhZXMoeCA9IEhvdXIsIHkgPSBEYXlPZldlZWssIGZpbGwgPSBub3JtKSkgKwogIGdlb21fdGlsZSgpICsKICAjIGZ0ZV90aGVtZSgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNiwgc2l6ZSA9IDQpKSArCiAgbGFicyh4ID0gIkhvdXIgb2YgQXJyZXN0IChMb2NhbCBUaW1lKSIsIHkgPSAiRGF5IG9mIFdlZWsgb2YgQXJyZXN0IiwgdGl0bGUgPSAiUG9saWNlIEFycmVzdHMgaW4gU2FuIEZyYW5jaXNjbyBmcm9tIDIwMDPigJMyMDE4IGJ5IFRpbWUgb2YgQXJyZXN0LCBOb3JtYWxpemVkIGJ5IE1vbnRoIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICIjRTc0QzNDIikgKwogIGZhY2V0X3dyYXAofiBNb250aCwgbnJvdyA9IDQpCnBsb3RfbW9udGhseQpgYGAKCiMjIyBGYWN0b3IgQnkgWWVhcgoKUGVyaGFwcyB0aGluZ3MgY2hhbmdlZCBvdmVydGltZT8KYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGZfYXJyZXN0X3RpbWVfeWVhciA8LSBkZl9hcnJlc3QgJT4lCiAgbXV0YXRlKFllYXIgPSBmb3JtYXQoYXMuRGF0ZShEYXRlLCAiJW0vJWQvJVkiKSwgIiVZIiksIEhvdXIgPSBzYXBwbHkoVGltZSwgZ2V0X2hvdXIpKSAlPiUKICBncm91cF9ieShZZWFyLCBEYXlPZldlZWssIEhvdXIpICU+JSAKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIG11dGF0ZShub3JtID0gY291bnQvc3VtKGNvdW50KSkKCmRmX2FycmVzdF90aW1lX3llYXIkRGF5T2ZXZWVrIDwtIGZhY3RvcihkZl9hcnJlc3RfdGltZV95ZWFyJERheU9mV2VlaywgbGV2ZWwgPSByZXYoZG93X2Zvcm1hdCkpCmRmX2FycmVzdF90aW1lX3llYXIkSG91ciA8LSBmYWN0b3IoZGZfYXJyZXN0X3RpbWVfeWVhciRIb3VyLCBsZXZlbCA9IDA6MjMsIGxhYmVsID0gaG91cl9mb3JtYXQpCgpwbG90X3llYXJseSA8LSBnZ3Bsb3QoZGZfYXJyZXN0X3RpbWVfeWVhciwgYWVzKHggPSBIb3VyLCB5ID0gRGF5T2ZXZWVrLCBmaWxsID0gbm9ybSkpICsKICBnZW9tX3RpbGUoKSArCiAgIyBmdGVfdGhlbWUoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjYsIHNpemUgPSA0KSkgKwogIGxhYnMoeCA9ICJIb3VyIG9mIEFycmVzdCAoTG9jYWwgVGltZSkiLCB5ID0gIkRheSBvZiBXZWVrIG9mIEFycmVzdCIsIHRpdGxlID0gIlBvbGljZSBBcnJlc3RzIGluIFNhbiBGcmFuY2lzY28gYnkgVGltZSBvZiBBcnJlc3QsIE5vcm1hbGl6ZWQgYnkgWWVhciAoMjAwMy0yMDE4KSIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAiI0U2N0UyMiIpICsKICBmYWNldF93cmFwKH4gWWVhciwgbnJvdyA9IDYpCnBsb3RfeWVhcmx5CmBgYAoKIyMgU3BhdGlvdGVtcG9yYWwgVHJlbmRzCiMjIyBBbmFseXplIENyaW1lIEhvdCBTcG90cwoKKiBDcmVhdGUgU3BhY2UgVGltZSBDdWJlIEJ5IEFnZ3JlZ2F0aW5nIFBvaW50cwoKKiBFbWVyZ2luZyBIb3QgU3BvdCBBbmFseXNpcwoKIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vbWJGZXNjVy5wbmcpCgohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9IQzlCOVVwLnBuZykKCgojIyMgRW5oYW5jZSBEYXRhIExheWVyCkFkZCBhZGRpdGlvbmFsIGF0dHJpYnV0ZXMgdG8gdGhlIGRhdGFzZXQuCgohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9qc0VZUjNOLnBuZykKCiMjIyBPcHRpbWl6ZWQgSG90IFNwb3QgQW5hbHlzaXMKSWRlbnRpZnkgYXJlYXMgd2l0aCB1bnVzdWFsbHkgaGlnaCBjcmltZSByYXRlcy4KCiFbXShodHRwczovL2kuaW1ndXIuY29tL2NUbGduSFAucG5nKQoKIyMjIENvcnJlbGF0aW9uIEFuYWx5c2lzCiFbXShodHRwczovL2kuaW1ndXIuY29tL1hLdkM3UE0ucG5nKQoKIyMgUmVmZXJlbmNlcwoKKiBbU2FuIEZyYW5jaXNjbyBDcmltZSBEYXRhXShodHRwczovL2RhdGEuc2Znb3Yub3JnL1B1YmxpYy1TYWZldHkvUG9saWNlLURlcGFydG1lbnQtSW5jaWRlbnQtUmVwb3J0cy1IaXN0b3JpY2FsLTIwMDMvdG1uZi15dnJ5L2RhdGEpCgoqIFtBbmFseXppbmcgIFNGIENyaW1lIERhdGFdKGh0dHA6Ly9taW5pbWF4aXIuY29tLzIwMTUvMTIvc2YtYXJyZXN0cy8pCgoqIFtBbmFseXplIENyaW1lIFVzaW5nIFN0YXRpc3RpY3MgYW5kIHRoZSBSLUFyY0dJUyBCcmlkZ2VdKGh0dHA6Ly9sZWFybi5hcmNnaXMuY29tL2VuL3Byb2plY3RzL2FuYWx5emUtY3JpbWUtdXNpbmctc3RhdGlzdGljcy1hbmQtdGhlLXItYXJjZ2lzLWJyaWRnZS8pCg==